<!-- file-view  docx/pdf/video/image-->
<template>
  <div
    class="file-view"
    :class="[
      {
        '!min-w-850px !min-h-600px': currentType === 'pdf',
        'w-full': currentType === 'xlsx'
      }
    ]"
    v-loading="loading"
    element-loading-text="加载中..."
  >
    <component
      ref="instanceRef"
      class="file-view-component"
      fit="contain"
      v-if="currentComponent && loadState !== 'error'"
      v-bind="props"
      :is="currentComponent"
      controls
      autoplay
      @rendered="renderedHandler"
      @error="errorHandler"
      @canplay="renderedHandler"
      @load="renderedHandler"
    />
    <el-empty v-if="loadState === 'error'" :image-size="200" description="加载失败" />
  </div>
</template>

<script setup lang="ts">
import { ElImage } from 'element-plus'
import { getFileExtensionByUrl, findType } from './utils'
import { pxToViewport } from '@/utils/formatter'
defineOptions({ name: 'FileView' })
const props = defineProps({
  // 文件类型 docx/pdf/video/image
  type: {
    type: String,
    default: ''
  },
  // 文件地址
  src: {
    type: String,
    default: ''
  }
})
const emits = defineEmits(['rendered', 'error'])
const loading = ref(false)
const loadState = ref('')
const instanceRef = ref<any>(null)
const componentMap = reactive({
  docx() {
    import('@vue-office/docx/lib/index.css')
    return defineAsyncComponent(() => import('@vue-office/docx'))
  },
  pdf() {
    return defineAsyncComponent(() => import('@vue-office/pdf'))
  },
  xlsx() {
    import('@vue-office/excel/lib/index.css')
    return defineAsyncComponent(() => import('@vue-office/excel'))
  },
  video() {
    return 'video'
  },
  image() {
    return ElImage
  }
})
const setLoading = (val: boolean) => {
  loading.value = val
}

const currentType: any = computed(() => {
  const extension = getFileExtensionByUrl(props.src)
  return props.type || findType(extension)
})
const currentComponent = computed(() => {
  const fn = componentMap[currentType.value]
  if (fn) {
    setLoading(true)
  }
  return fn?.()
})

// 设置行内样式pt转vw(docx)
const resetStyle = (ele: any) => {
  const elements: any = ele?.querySelectorAll('[style*="pt"]')
  // 1pt = 1.333px (标准转换比例)
  const ptToPxRatio = 4 / 3
  // 正则表达式匹配行内样式中的 pt 单位值
  const ptRegex = /(\d*\.?\d+)pt/g
  for (const element of elements) {
    let styleContent = element.getAttribute('style')
    if (!!styleContent) {
      styleContent = styleContent.replace(ptRegex, (ptMatch, ptValue) => {
        const ptNum = parseFloat(ptValue)
        if (isNaN(ptNum)) return ptMatch
        const pxValue = ptNum * ptToPxRatio
        return pxToViewport(pxValue)
      })
      element.setAttribute('style', styleContent)
    }
  }
}
const renderedHandler = () => {
  console.log('rendered')
  if (instanceRef?.value?.$el) {
    resetStyle(instanceRef.value?.$el)
  }
  loading.value = false
  emits('rendered')
}
const errorHandler = (error) => {
  console.log('error', error, error.type)
  if (error?.message?.includes('Failed') || error?.type?.includes('error')) {
    loading.value = false
    loadState.value = 'error'
  }
  emits('error', error)
}
defineExpose({
  instanceRef
})
</script>

<style lang="scss" scoped>
.file-view {
  display: flex;
  height: 100%;
  min-width: 100px;
  min-height: 100px;

  .file-view-component {
    // flex-shrink: 0;
    flex: 1;
  }

  video {
    width: 100%;
    background-color: #000;
  }

  // :deep(.docx) {

  // }
}
</style>
